package com.tql.mall.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tql.mall.cart.client.CartFeignClient;
import com.tql.mall.common.constant.PageConstant;
import com.tql.mall.common.constant.RedisConstant;
import com.tql.mall.common.result.R;
import com.tql.mall.common.util.ComUtil;
import com.tql.mall.merchant.client.MerchantFeignClient;
import com.tql.mall.model.cart.CartInfo;
import com.tql.mall.model.customer.Customer;
import com.tql.mall.model.customer.CustomerAddr;
import com.tql.mall.model.enums.OrderStatus;
import com.tql.mall.model.enums.PaymentWay;
import com.tql.mall.model.enums.ProcessStatus;
import com.tql.mall.model.order.OrderDetail;
import com.tql.mall.model.order.OrderInfo;
import com.tql.mall.model.order.ReturnInfo;
import com.tql.mall.order.mapper.OrderDetailMapper;
import com.tql.mall.order.mapper.OrderInfoMapper;
import com.tql.mall.order.mapper.ReturnInfoMapper;
import com.tql.mall.order.service.OrderService;
import com.tql.mall.product.client.ProductFeignClient;
import com.tql.mall.rabbit.constant.MqConstant;
import com.tql.mall.rabbit.service.RabbitService;
import com.tql.mall.user.client.UserFeignClient;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @Author: tyk
 * @Date: 2023/5/26 17:38
 * @Description:
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private ReturnInfoMapper returnInfoMapper;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private CartFeignClient cartFeignClient;
    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private MerchantFeignClient merchantFeignClient;


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

//       @Autowired
//       private StockFeignClient stockFeignClient;

    @Autowired
    private ThreadPoolExecutor executor;


    @Override
    public Map<String, Object> trade(String userId) {

        HashMap<String, Object> res = new HashMap<>();

        // 收货地址列表
        List<CustomerAddr> userAddrList = userFeignClient.getCustomerAddrList(Long.parseLong(userId));
        res.put(PageConstant.USER_ADDR_LIST, userAddrList);

        // 商品列表
        List<CartInfo> cartInfoList = cartFeignClient.getCartCheckedList(userId);

        // 商品列表封装成订单明细
        List<OrderDetail> detailList;
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            // 订单明细
            detailList = cartInfoList.stream().map(e -> {
                OrderDetail detail = new OrderDetail();
                detail.setSkuId(e.getSkuId());
                detail.setSkuName(e.getSkuName());
                detail.setImgUrl(e.getImgUrl());
                detail.setOrderPrice(productFeignClient.getSkuPrice(e.getSkuId()));
                detail.setSkuNum(e.getSkuNum());
                detail.setShopId(e.getShopId());
                return detail;
            }).collect(Collectors.toList());
            res.put(PageConstant.DETAIL_LIST, detailList);
            // 订单数量
            res.put(PageConstant.TOTAL_NUM, detailList.size());
            // 订单总金额
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setOrderDetailList(detailList);
            orderInfo.sumTotalAmount();
            res.put(PageConstant.TOTAL_AMOUNT, orderInfo.getTotalAmount());
        }

        // 携带流水号
        res.put(PageConstant.TRADE_NO, getTradeNo(userId));

        return res;
    }

    @Override
    public Long submitOrder(OrderInfo orderInfo) {

        // 父订单设置为0（表示本身就是父订单）
        orderInfo.setParentOrderId(0L);
        // 收件人信息
        Customer customer = userFeignClient.getCustomer(orderInfo.getUserId());
        orderInfo.setConsignee(customer.getName());
        orderInfo.setConsigneeTel(customer.getPhone());
        // 总金额
        orderInfo.sumTotalAmount();
        // 订单状态
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        // 支付方式
        orderInfo.setPaymentWay(PaymentWay.ONLINE.name());
        // 订单交易号
        orderInfo.setOutTradeNo(ComUtil.uuid());
        // 订单描述
        StringBuilder builder = new StringBuilder();
        for (OrderDetail detail : orderInfo.getOrderDetailList())
            builder.append(detail.getSkuName()).append(" ");
        if (builder.length() > 100) orderInfo.setTradeBody(builder.substring(0, 100));
        else orderInfo.setTradeBody(builder.toString());
        // 操作时间
        orderInfo.setOperateTime(new Date());
        // 失效时间
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 1);
        orderInfo.setExpireTime(calendar.getTime());
        // 进度状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());

        // 保存订单
        orderInfoMapper.insert(orderInfo);

        // 保存订单明细
        for (OrderDetail detail : orderInfo.getOrderDetailList()) {
            // 设置订单ID
            detail.setOrderId(orderInfo.getId());
            // 添加
            orderDetailMapper.insert(detail);
        }

        // 删除购物车中已选中的商品
        cartFeignClient.deleteCartCheckedList(orderInfo.getUserId().toString());

        // 延时取消订单
        rabbitService.sendDelayMsg(
                MqConstant.EXCHANGE_ORDER_CANCEL,
                MqConstant.ROUTING_ORDER_CANCEL,
                orderInfo.getId(),
                MqConstant.ORDER_DELAY_TIME);

        // 返回订单ID
        return orderInfo.getId();
    }

    @Override
    public String getTradeNo(String userId) {
        // 流水号
        String tradeNo = ComUtil.uuid();
        // 存储到Redis
        String tradeNoKey = getTradeNoKey(userId);
        redisTemplate.opsForValue().set(tradeNoKey, tradeNo);
        // 返回到页面
        return tradeNo;
    }


    @Override
    public Boolean checkTradeCode(String userId, String tradeNoCode) {
        String tradeNoRedis = (String) redisTemplate.opsForValue().get(getTradeNoKey(userId));
        return tradeNoCode.equals(tradeNoRedis);
    }

    @Override
    public void deleteTradeCode(String userId) {
        redisTemplate.delete(getTradeNoKey(userId));
    }

    @Override
    public R checkOrder(String userId, String tradeNo, OrderInfo orderInfo) {
        // 校验流水号
        if (!checkTradeCode(userId, tradeNo)) {
            return R.fail().msg("订单不能重复提交");
        }
        // 收集异步对象
        List<CompletableFuture> cfList = new ArrayList<>();
        // 收集错误信息
        List<String> errorList = new ArrayList<>();

        // 校验库存和价格
        for (OrderDetail e : orderInfo.getOrderDetailList()) {
//            // 校验库存（异步编排）
//            CompletableFuture<Void> stockCf = CompletableFuture.runAsync(() -> {
//                // 校验库存
//                Boolean flag = merchantFeignClient.checkStock(new StockInfoQueryVo(e.getSkuId(), e.getShopId(), e.getSkuNum()));
//                if (!flag)
//                    errorList.add(e.getSkuName() + "库存不足!");
//            }, executor);
//            cfList.add(stockCf);

            // 校验价格（异步编排）
            CompletableFuture<Void> prickCf = CompletableFuture.runAsync(() -> {
                // 校验价格
                BigDecimal skuPrice = productFeignClient.getSkuPrice(e.getSkuId());
                if (skuPrice.compareTo(e.getOrderPrice()) != 0) {
                    // 更新价格
                    List<CartInfo> cartCheckedList = cartFeignClient.getCartCheckedList(userId);
                    BoundHashOperations<String, String, CartInfo> bound = redisTemplate.boundHashOps(RedisConstant.CART_PREFIX + userId);
                    for (CartInfo cartInfo : cartCheckedList) {
                        bound.put(cartInfo.getSkuId().toString(), cartInfo);
                    }
                    // 结算失败
                    errorList.add(e.getSkuName() + "价格变动，请重试");
                }
            }, executor);
            cfList.add(prickCf);
        }

        // 任务组合
        CompletableFuture.allOf(cfList.toArray(new CompletableFuture[0])).join();

        // 错误集合信息
        if (!errorList.isEmpty())
            return R.fail().msg(StringUtils.join(errorList, ","));

        return R.ok();
    }

    @Override
    public IPage<OrderInfo> getOrderList(String userId, Page<OrderInfo> pageInfo) {
        IPage<OrderInfo> orderInfoIPage = orderInfoMapper.selectOrderList(userId, pageInfo);
        // 设置订单状态名称
        orderInfoIPage.getRecords().forEach(e -> {
            e.setOrderStatusName(OrderStatus.getStatusNameByStatus(e.getOrderStatus()));
        });
        return orderInfoIPage;
    }

    @Override
    public void execExpireOrder(Long orderId) {
        // 关闭订单
        updateOrderStatus(orderId, ProcessStatus.CLOSED);
    }

    @Override
    public void updateOrderStatus(Long orderId, ProcessStatus status) {
        OrderInfo orderInfo = new OrderInfo();
        // 订单ID
        orderInfo.setId(orderId);
        // 修改订单状态
        orderInfo.setOrderStatus(status.getOrderStatus().name());
        // 修改处理进度
        orderInfo.setProcessStatus(status.name());
        // 执行修改
        orderInfoMapper.updateById(orderInfo);
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        // 查询订单
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        // 查询订单详情
        if (orderInfo != null) {
            LambdaQueryWrapper<OrderDetail> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OrderDetail::getOrderId, orderId);
            List<OrderDetail> detailList = orderDetailMapper.selectList(wrapper);
            orderInfo.setOrderDetailList(detailList);
        }
        return orderInfo;
    }

    @Override
    public void returnGood(ReturnInfo returnInfo) {
        // 更新订单状态
        updateOrderStatus(returnInfo.getOrderId(), ProcessStatus.WAIT_RETURN);
        // 添加退货记录
        returnInfoMapper.insert(returnInfo);
    }

    @Override
    public void splitOrder(OrderInfo orderInfo) {
        orderInfo.getOrderDetailList().forEach(e -> {
            OrderInfo order = new OrderInfo(orderInfo);
            // 订单详情
            order.setOrderDetailList(Collections.singletonList(e));
            // 金额
            order.setTotalAmount(e.amount());
            // 父订单
            order.setParentOrderId(orderInfo.getId());
            // 店铺ID
            order.setShopId(e.getShopId());
            // 保存子订单
            orderInfoMapper.insert(order);
            // 修改订单明细所属订单
            e.setOrderId(order.getId());
            orderDetailMapper.updateById(e);
        });
        // 将该订单标记为已拆单
        orderInfo.setParentOrderId(-1L);
        orderInfo.setOrderStatus(OrderStatus.SPLIT.name());
        orderInfoMapper.updateById(orderInfo);
    }

    @Override
    public IPage<OrderInfo> getOrderListForShop(Long shopId, Page<OrderInfo> pageInfo) {
        // 查询订单
        IPage<OrderInfo> orderInfoIPage = orderInfoMapper.selectOrderListForShop(shopId, pageInfo);
        // 设置订单状态名称
        orderInfoIPage.getRecords().forEach(e -> {
            e.setOrderStatusName(OrderStatus.getStatusNameByStatus(e.getOrderStatus()));
        });
        return orderInfoIPage;
    }

    /**
     * 生成流水号的key
     */
    private String getTradeNoKey(String userId) {
        return RedisConstant.ORDER_TRADE_NO + userId;
    }

}
